///////////////////////////////////////////////////////////////////////////////
//
// Depth-First Search Maze Generator
//
// Original program written by Mike Gold, September 2005
// See Mike's page at:
// http://www.microgold.com
// Code available in MazeGenerator.ZIP from:
// http://www.gamespp.com/c/generatingMazes.html
// or from the C# Corner as dfsmaze.zip:
// http://www.c-sharpcorner.com/UploadFile/mgold/Maze09222005021857AM/Maze.aspx
//
// See also
// http://www.mazeworks.com/mazegen/mazetut/
// for an explanation of how mazes can be generated
//
// Modified by Trevor Taylor, Feb 2008
//
// Changes:
// Adjusted some of the initial parameters
// Created a separate menu item to set the maze parameters
// Renamed Form1 to MainForm
// Added a PictureBox for the Maze instead of drawing onto the Form
// (Required different handling for Paint and Resize events)
// Adjusted padding around the maze to be more even
// Added random Start and Finish cells (marked in green and red)
// (Which required a wall color parameter for drawing cells)
// Added Wall Thickness and allowed user to change it
// Added Save As menu option to save the bitmap
// Added Point-and-click to find out cell/pixel coords on the maze
// Created an icon using the generator itself
//
///////////////////////////////////////////////////////////////////////////////


using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace DFSAlgorithmMaze
{
	/// <summary>
	/// Summary description for Form1.
	/// </summary>
	public class MainForm : System.Windows.Forms.Form
	{
        private IContainer components;
        // maze array
		private System.Drawing.Printing.PrintDocument printDocument1;
		private System.Windows.Forms.PrintPreviewDialog printPreviewDialog1;
		private System.Windows.Forms.MainMenu mainMenu1;
		private System.Windows.Forms.MenuItem FileMenu;
		private System.Windows.Forms.MenuItem PrintMenu;
		private System.Windows.Forms.MenuItem PreviewMenu;
		private System.Windows.Forms.MenuItem DimensionsMenu;
        private MenuItem ExitMenu;
        private MenuItem OptionsMenu;
        private MenuItem MazeDimensionsMenu;
        private MenuItem SaveAsMenu;
        private PictureBox picMaze;
        private SaveFileDialog saveFileDialog1;
		private Maze TheMaze  = new Maze();

		public MainForm()
		{
			//
			// Required for Windows Form Designer support
			//
			InitializeComponent();
            // TT
			//SetBounds(this.Left, this.Top, (Maze.kDimension + 2) * Cell.kCellSize + Cell.kPadding , (Maze.kDimension + 5) * Cell.kCellSize + Cell.kPadding);
            //SetBounds(this.Left, this.Top, (Maze.kDimension + 2) * Cell.kCellSize + Cell.kPadding, (Maze.kDimension + 4) * Cell.kCellSize + Cell.kPadding);
            SetWindowSize();
            this.Cursor = Cursors.WaitCursor;
			TheMaze.Generate();
			this.Cursor = Cursors.Arrow;

			//
			// TODO: Add any constructor code after InitializeComponent call
			//
		}

        private void Form1_Load(object sender, EventArgs e)
        {
            TheMaze.Initialize();
            TheMaze.Generate();
            SetWindowSize();
            //Invalidate();
            DrawMaze();
        }

        /// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if (components != null) 
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		#region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
            this.components = new System.ComponentModel.Container();
            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
            this.printDocument1 = new System.Drawing.Printing.PrintDocument();
            this.printPreviewDialog1 = new System.Windows.Forms.PrintPreviewDialog();
            this.mainMenu1 = new System.Windows.Forms.MainMenu(this.components);
            this.FileMenu = new System.Windows.Forms.MenuItem();
            this.DimensionsMenu = new System.Windows.Forms.MenuItem();
            this.PrintMenu = new System.Windows.Forms.MenuItem();
            this.PreviewMenu = new System.Windows.Forms.MenuItem();
            this.SaveAsMenu = new System.Windows.Forms.MenuItem();
            this.ExitMenu = new System.Windows.Forms.MenuItem();
            this.OptionsMenu = new System.Windows.Forms.MenuItem();
            this.MazeDimensionsMenu = new System.Windows.Forms.MenuItem();
            this.picMaze = new System.Windows.Forms.PictureBox();
            this.saveFileDialog1 = new System.Windows.Forms.SaveFileDialog();
            ((System.ComponentModel.ISupportInitialize)(this.picMaze)).BeginInit();
            this.SuspendLayout();
            // 
            // printDocument1
            // 
            this.printDocument1.PrintPage += new System.Drawing.Printing.PrintPageEventHandler(this.printDocument1_PrintPage);
            // 
            // printPreviewDialog1
            // 
            this.printPreviewDialog1.AutoScrollMargin = new System.Drawing.Size(0, 0);
            this.printPreviewDialog1.AutoScrollMinSize = new System.Drawing.Size(0, 0);
            this.printPreviewDialog1.ClientSize = new System.Drawing.Size(400, 300);
            this.printPreviewDialog1.Document = this.printDocument1;
            this.printPreviewDialog1.Enabled = true;
            this.printPreviewDialog1.Icon = ((System.Drawing.Icon)(resources.GetObject("printPreviewDialog1.Icon")));
            this.printPreviewDialog1.Name = "printPreviewDialog1";
            this.printPreviewDialog1.Visible = false;
            // 
            // mainMenu1
            // 
            this.mainMenu1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
            this.FileMenu,
            this.OptionsMenu});
            // 
            // FileMenu
            // 
            this.FileMenu.Index = 0;
            this.FileMenu.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
            this.DimensionsMenu,
            this.PrintMenu,
            this.PreviewMenu,
            this.SaveAsMenu,
            this.ExitMenu});
            this.FileMenu.Text = "&File";
            // 
            // DimensionsMenu
            // 
            this.DimensionsMenu.Index = 0;
            this.DimensionsMenu.Text = "&Generate New Maze";
            this.DimensionsMenu.Click += new System.EventHandler(this.DimensionsMenu_Click);
            // 
            // PrintMenu
            // 
            this.PrintMenu.Index = 1;
            this.PrintMenu.Text = "&Print";
            this.PrintMenu.Click += new System.EventHandler(this.PrintMenu_Click);
            // 
            // PreviewMenu
            // 
            this.PreviewMenu.Index = 2;
            this.PreviewMenu.Text = "Print Pre&view...";
            this.PreviewMenu.Click += new System.EventHandler(this.PreviewMenu_Click);
            // 
            // SaveAsMenu
            // 
            this.SaveAsMenu.Index = 3;
            this.SaveAsMenu.Text = "&Save As...";
            this.SaveAsMenu.Click += new System.EventHandler(this.SaveAsMenu_Click);
            // 
            // ExitMenu
            // 
            this.ExitMenu.Index = 4;
            this.ExitMenu.Text = "E&xit";
            this.ExitMenu.Click += new System.EventHandler(this.ExitMenu_Click);
            // 
            // OptionsMenu
            // 
            this.OptionsMenu.Index = 1;
            this.OptionsMenu.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
            this.MazeDimensionsMenu});
            this.OptionsMenu.Text = "&Options";
            // 
            // MazeDimensionsMenu
            // 
            this.MazeDimensionsMenu.Index = 0;
            this.MazeDimensionsMenu.Text = "Maze &Dimensions...";
            this.MazeDimensionsMenu.Click += new System.EventHandler(this.MazeDimensionsMenu_Click);
            // 
            // picMaze
            // 
            this.picMaze.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
                        | System.Windows.Forms.AnchorStyles.Left)
                        | System.Windows.Forms.AnchorStyles.Right)));
            this.picMaze.Cursor = System.Windows.Forms.Cursors.NoMove2D;
            this.picMaze.Location = new System.Drawing.Point(0, 0);
            this.picMaze.Name = "picMaze";
            this.picMaze.Size = new System.Drawing.Size(290, 270);
            this.picMaze.TabIndex = 0;
            this.picMaze.TabStop = false;
            this.picMaze.Click += new System.EventHandler(this.picMaze_Click);
            // 
            // saveFileDialog1
            // 
            this.saveFileDialog1.Filter = "Bitmap Files|*.bmp|GIF Files|*.gif|All Files|*.*";
            this.saveFileDialog1.Title = "Save Maze Image";
            this.saveFileDialog1.FileOk += new System.ComponentModel.CancelEventHandler(this.saveFileDialog1_FileOk);
            // 
            // Form1
            // 
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
            this.ClientSize = new System.Drawing.Size(292, 273);
            this.Controls.Add(this.picMaze);
            this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
            this.MaximizeBox = false;
            this.Menu = this.mainMenu1;
            this.Name = "Form1";
            this.Text = "Depth First Search Maze";
            this.Load += new System.EventHandler(this.Form1_Load);
            this.Resize += new System.EventHandler(this.Form1_Resize);
            ((System.ComponentModel.ISupportInitialize)(this.picMaze)).EndInit();
            this.ResumeLayout(false);

		}
		#endregion

		/// <summary>
		/// The main entry point for the application.
		/// </summary>
		[STAThread]
		static void Main() 
		{
			Application.Run(new MainForm());
		}

        // TT - Don't draw directly to the Form
        /*
		private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
		{
			Graphics g = e.Graphics;
		    g.FillRectangle(Brushes.White, ClientRectangle);
            TheMaze.Draw(g);
		}
        */

        private void DrawMaze()
        {
            Bitmap bm = new Bitmap(picMaze.Width, picMaze.Height);
            Graphics g = Graphics.FromImage(bm);
            g.FillRectangle(Brushes.White, ClientRectangle);
            TheMaze.Draw(g);
            picMaze.Image = bm;
        }

        // TT - This code appeared in three different places, so put it all here
        // where it can be more easily maintained
        private void SetWindowSize()
        {
            Point top = picMaze.PointToScreen(new Point(0, 0));
            int offsetX = top.X - this.Left;
            int offsetY = top.Y - this.Top;
            //SetBounds(this.Left, this.Top, (Maze.kDimension + 2) * Cell.kCellSize + Cell.kPadding, (Maze.kDimension + 5) * Cell.kCellSize + Cell.kPadding);
            // TT - kPadding is now locked to kCellSize, so it counts as an extra cell
            int width = (Maze.kDimension + 2) * Cell.kCellSize + Cell.kPadding/2 + offsetX;
            int height = (Maze.kDimension + 2) * Cell.kCellSize + Cell.kPadding/2 + offsetY;
            SetBounds(this.Left, this.Top, width, height);
        }

		private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
		{
			TheMaze.Draw(e.Graphics);		
		}

		private void PreviewMenu_Click(object sender, System.EventArgs e)
		{
		 this.printPreviewDialog1.ShowDialog();
		}

		private void PrintMenu_Click(object sender, System.EventArgs e)
		{
		  printDocument1.Print();
		}

		private void DimensionsMenu_Click(object sender, System.EventArgs e)
		{
            // TT - Set the dimensions separately
            /*
			DimensionsDialog theDialog = new DimensionsDialog();
			theDialog.numericUpDown1.Value = Maze.kDimension;
			theDialog.numericUpDown2.Value = Cell.kCellSize;
			if (theDialog.ShowDialog() == DialogResult.OK)
			{
				Maze.kDimension = 	(int)theDialog.numericUpDown1.Value;
				Cell.kCellSize =  (int)theDialog.numericUpDown2.Value;
             */
            TheMaze.Initialize();
			TheMaze.Generate();
            SetWindowSize();
            //Invalidate();
            DrawMaze();
//			}
		}

        private void ExitMenu_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void MazeDimensionsMenu_Click(object sender, EventArgs e)
        {
            DimensionsDialog theDialog = new DimensionsDialog();
            theDialog.numericUpDown1.Value = Maze.kDimension;
            theDialog.numericUpDown2.Value = Cell.kCellSize;
            theDialog.numericUpDown3.Value = Cell.WallThickness;
            if (theDialog.ShowDialog() == DialogResult.OK)
            {
                Maze.kDimension = (int)theDialog.numericUpDown1.Value;
                Cell.kCellSize = (int)theDialog.numericUpDown2.Value;
                // Added the WallThickness as a setting
                Cell.WallThickness = (int)theDialog.numericUpDown3.Value;
                // Make the padding equal to one cell
                Cell.kPadding = Cell.kCellSize;
                TheMaze.Initialize();
                TheMaze.Generate();
                SetWindowSize();
                //Invalidate();
                DrawMaze();
            }

        }

        // TT - Added a Save As menu option
        private void SaveAsMenu_Click(object sender, EventArgs e)
        {
            saveFileDialog1.ShowDialog();
        }

        private void saveFileDialog1_FileOk(object sender, CancelEventArgs e)
        {
            picMaze.Image.Save(saveFileDialog1.FileName);
        }

        // TT - Don't use Paint because it interferes with Message Boxes!
        /*
        private void picMaze_Paint(object sender, PaintEventArgs e)
        {
            Bitmap bm = new Bitmap(picMaze.Width, picMaze.Height);
            Graphics g = Graphics.FromImage(bm);
            //Graphics g = e.Graphics;
            g.FillRectangle(Brushes.White, ClientRectangle);
            TheMaze.Draw(g);
            picMaze.Image = bm;
        }
        */

        // TT - Allow user to point to a cell and click on it to see where it is
        private void picMaze_Click(object sender, EventArgs e)
        {
            Point p = picMaze.PointToClient(new Point(Cursor.Position.X, Cursor.Position.Y));
            int x = (int) (p.X / Cell.kCellSize);
            int y = (int) (p.Y / Cell.kCellSize);
            MessageBox.Show("Pixel " + p.X + "," + p.Y + "\nCell " + x + "," + y, "Location");
        }

        // TT - Need to redraw on a resize now that Paint is not used
        private void Form1_Resize(object sender, EventArgs e)
        {
            // Unfortunately, there is a Resize message when the window
            // is minimized so ignore this
            if (this.WindowState == FormWindowState.Normal)
                DrawMaze();
        }

	}
}
